package XunChunCPU

import chisel3._
import XunChunCPU.common.CommonConfig._
import XunChunCPU.common.Bundles._
import XunChunCPU.IF._
import XunChunCPU.ID._
import XunChunCPU.EXE._
import XunChunCPU.MEM._
import XunChunCPU.WB._


class XunChunTop extends Module {
    val io = IO(new Bundle{
        val if_rdata = Input(UInt(32.W))
        val mem_rdata = Input(UInt(32.W))
        // 输出
        val if_addr = Output(UInt(32.W))
        val mem_addr = Output(UInt(32.W))
        val mem_wr = Output(Bool())
        val mem_size = Output(UInt(2.W))
        val mem_wdata = Output(UInt(32.W))
    })

    // IF
    val pc = Module(new PC)
    // ID
    val idreg = Module(new IDReg)
    val decode = Module(new Decode)
    val control = Module(new Control)
    // EXE
    val exereg = Module(new EXEReg)
    val alu = Module(new ALU)
    val mulmodule = Module(new MulModule)
    // MEM
    val memreg = Module(new MEMReg)
    val memaccess = Module(new MemAccess)
    // WB
    val wbreg = Module(new WBReg)
    // RegFile
    val regfile = Module(new RegFile)
    
    // 连线
    // pc 的输入
    pc.io.ready_in := idreg.io.ready_out
    pc.io.NPC_Type := control.io.NPC_Type
    pc.io.pcImm := control.io.NextPC
    pc.io.stall := control.io.stallFromID || alu.io.stallFromEXE || memaccess.io.stallFromMEM
    
    // idreg的输入
    idreg.io.pc_in := pc.io.pc
    idreg.io.instr_in := io.if_rdata
    idreg.io.valid_in := pc.io.valid_out
    idreg.io.ready_in := decode.io.ready_out
    idreg.io.stallFromIF := control.io.stallFromID
    idreg.io.stallFromEXE := alu.io.stallFromEXE
    idreg.io.stallFromMEM := memaccess.io.stallFromMEM

    // decode的输入
    decode.io.instr_in := idreg.io.instr_out
    decode.io.pc_in := idreg.io.pc_out
    decode.io.ready_in := control.io.ready_out

    // control的输入
    control.io.controlInfo <> decode.io.controlInfo
    control.io.instr := decode.io.instr_out
    control.io.pc := decode.io.pc_out
    control.io.rsData := regfile.io.read.rsData
    control.io.rtData := regfile.io.read.rtData
    control.io.bypassFromExe <> alu.io.bypassFromExe
    control.io.bypassFromMem <> memaccess.io.bypassFromMem1
    control.io.isLBandLW := alu.io.isLBandLW
    control.io.wregAddr := alu.io.wregAddr
    control.io.valid_in := idreg.io.valid_out
    control.io.ready_in := exereg.io.ready_out

    // exereg的输入
    exereg.io.exeInfo_in <> control.io.exeInfo
    exereg.io.valid_in := control.io.valid_out
    exereg.io.ready_in := alu.io.ready_out

    // alu的输入
    alu.io.exeInfo <> exereg.io.exeInfo_out
    alu.io.bypassFromMem2 <> memaccess.io.bypassFromMem2
    alu.io.mulans := mulmodule.io.ans

    // mulmodule的输入
    mulmodule.io.OpA := alu.io.OpA
    mulmodule.io.OpB := alu.io.OpB

    // memreg的输入
    memreg.io.memInfo_in <> alu.io.memInfo
    memreg.io.wbInfo_in <> alu.io.wbInfo
    memreg.io.valid_in := alu.io.valid_out

    // memaccess的输入
    memaccess.io.memInfo <> memreg.io.memInfo_out
    memaccess.io.wbInfo_in <> memreg.io.wbInfo_out
    memaccess.io.rdata := io.mem_rdata

    // wbreg的输入
    wbreg.io.wbInfo <> memaccess.io.wbInfo_out

    // regfile的输入
    regfile.io.read.rsAddr := control.io.rsAddr
    regfile.io.read.rtAddr := control.io.rtAddr
    regfile.io.write <> wbreg.io.write

    // 顶层文件的输入
    // 如果不阻塞，那么if_addr就是npc,否则是原来的pc
    when(control.io.ready_out && !control.io.stallFromID && !alu.io.stallFromEXE && !memaccess.io.stallFromMEM && alu.io.ready_out){
        io.if_addr := pc.io.npc
    }.otherwise{
        io.if_addr := pc.io.pc
    }

    io.mem_addr := alu.io.addr
    io.mem_wr := alu.io.wr
    io.mem_size := alu.io.size
    io.mem_wdata := alu.io.wdata
}